/**
 * 
 */
package com.intelap.fabricaciones;

import java.io.Serializable;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.Arrays;
import java.util.logging.Logger;

import javax.annotation.Resource;
import javax.inject.Inject;
import javax.interceptor.AroundInvoke;
import javax.interceptor.Interceptor;
import javax.interceptor.InterceptorBinding;
import javax.interceptor.InvocationContext;
import javax.transaction.HeuristicMixedException;
import javax.transaction.HeuristicRollbackException;
import javax.transaction.NotSupportedException;
import javax.transaction.RollbackException;
import javax.transaction.Status;
import javax.transaction.SystemException;
import javax.transaction.UserTransaction;

/** @author Gustavo */
@Interceptor
@InterceptorTransaccional.Transaccional
public class InterceptorTransaccional implements Serializable {
	@Inject
	private Logger logger;
	@Resource
	private UserTransaction tx;
	@Inject
	private UnidadTrabajo ut;

	@AroundInvoke
	public Object manejarTransaction(InvocationContext ctx) throws Exception {
		try {
			Object resultado;
			int estadoTransaccionExterna = tx.getStatus();
			if (estadoTransaccionExterna == Status.STATUS_ACTIVE) {
				ut.unirseATransaccion();
				resultado = ctx.proceed();
			} else if (estadoTransaccionExterna == Status.STATUS_NO_TRANSACTION) {
				try {
					logger.info("comienzo transaccion");
					tx.begin();
					try {
						ut.unirseATransaccion();
						resultado = ctx.proceed();
					} catch (RuntimeException e2) {
						tx.rollback();
						throw e2;
					}
					tx.commit();
					logger.info("fin transaccion exitoso");
				} catch (NotSupportedException | SystemException | RollbackException | HeuristicMixedException | HeuristicRollbackException e1) {
					throw new RuntimeException("El manejo de la transacción para el metodo transaccional '" + ctx.getMethod() + "' sobre '" + ctx.getTarget()
							+ "' con parametros '" + Arrays.toString(ctx.getParameters()) + "' lanzó la siguiente excepcion:", e1);
				}
			} else {
				throw new IllegalStateException("Estado illegal de la transaccion (status=" + estadoTransaccionExterna
						+ ") en la llamada al metodo transaccional '" + ctx.getMethod() + "' sobre '" + ctx.getTarget());
			}
			return resultado;
		} catch (RuntimeException e0) {
			ut.abortar();
			throw e0;
		}
	}

	@InterceptorBinding
	@Inherited
	@Target({ ElementType.METHOD, ElementType.TYPE })
	@Retention(RetentionPolicy.RUNTIME)
	public @interface Transaccional {}
}
